import ij.IJ;
import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.Blitter;
import ij.process.ByteProcessor;
import ij.process.ColorBlitter;
import ij.process.ColorProcessor;
//import ij.process.DecomiteProcessor;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
import ij.process.ShortProcessor;


import java.awt.Color;


import java.awt.Font;

import java.awt.Polygon;
import java.io.PrintStream;

import java.util.ArrayList;
import java.util.Locale;
import java.util.Random; 

import pluginUtils.geneticAlgorithms.Cercle;
import pluginUtils.geneticAlgorithms.Genome;
import pluginUtils.geneticAlgorithms.Population;




public class MonaLisa extends ImagePlus implements PlugIn{
	{Locale.setDefault(Locale.US); }
	
	private ImageProcessor primeIP; 
	private int X=2000,Y=2000; // image size
	
	
	private double xShift=0; 
	private double zShift=0; 
	
	
	

	private static Random generator=new Random(); // One always needs some randomness
	
	// For the scaling of the image
	private double x0=0,x1=1,y0=0,y1=1;
	private double acoef,ccoef,vcoef,wcoef; 
	
	
	
	private String[] palette={"Yellow","Red","Blue","Green","White","NavyBlue","Turquoise","Orange"};
	private Color[] palette1={Color.YELLOW,Color.RED,Color.BLUE,Color.GREEN,Color.MAGENTA,Color.ORANGE};
	public void setCoefs(){
		acoef=X/(x1-x0); 
		vcoef=Y/(y1-y0); 
		ccoef=-acoef*x0; 
		wcoef=-vcoef*y0; 
	}
	 
	
	
	public void setBounds(double xl,double xu,double yl,double yu){
		x0=xl; 
		x1=xu;
		y0=yl;
		y1=yu; 
	}
	
	public static double fitness2(Genome hector,int[][] baseImage,int X,int Y){
		ImageProcessor drawing=new ColorProcessor(X,Y); 
		for(int i=0;i<hector.getLength();i++){
			Cercle ce=hector.get(i); 
			drawing.setColor(new java.awt.Color(ce.getRed(),ce.getGreen(),ce.getBlue()));
			drawing.fillOval(ce.getX(),ce.getY(),ce.getRadius(),ce.getRadius()); 
		}
		int[][] copie=drawing.getIntArray(); 
		double sum=0; 
		for(int ix=0;ix<X;ix+=X/15){
			for(int iy=0;iy<Y;iy+=Y/15){
			int redA=(baseImage[ix][iy] & 0xff0000)>>16; 
			int greenA=(baseImage[ix][iy]  & 0x00ff00)>>8; 
			int blueA=baseImage[ix][iy]  & 0x0000ff; 
			int redB=(copie[ix][iy] & 0xff0000)>>16; 
			int greenB=(copie[ix][iy]  & 0x00ff00)>>8; 
			int blueB=copie[ix][iy]  & 0x0000ff; 
			sum+=Math.abs(redA-redB)/256.0; 
			sum+=Math.abs(greenA-greenB)/256.0; 
			sum+=Math.abs(blueA-blueB)/256.0; 
		}
		}
		return 1/sum; 
	}
	
	public static double fitness(Genome hector,int[][] baseImage,int X,int Y){
		ImageProcessor drawing=new ColorProcessor(X,Y); 
		for(int i=0;i<hector.getLength();i++){
			Cercle ce=hector.get(i); 
			drawing.setColor(new java.awt.Color(ce.getRed(),ce.getGreen(),ce.getBlue()));
			drawing.fillOval(ce.getX(),ce.getY(),ce.getRadius(),ce.getRadius()); 
		}
		int[][] copie=drawing.getIntArray(); 
		double sum=0; 
		for(int i=0;i<10000;i++){
			int ix=MonaLisa.generator.nextInt(X);
			int iy=MonaLisa.generator.nextInt(Y);
			int redA=(baseImage[ix][iy] & 0xff0000)>>16; 
			int greenA=(baseImage[ix][iy]  & 0x00ff00)>>8; 
			int blueA=baseImage[ix][iy]  & 0x0000ff; 
			int redB=(copie[ix][iy] & 0xff0000)>>16; 
			int greenB=(copie[ix][iy]  & 0x00ff00)>>8; 
			int blueB=copie[ix][iy]  & 0x0000ff; 
			sum+=Math.abs(redA-redB)/256.0; 
			sum+=Math.abs(greenA-greenB)/256.0; 
			sum+=Math.abs(blueA-blueB)/256.0; 
		}
		return 1/sum; 
	}

	
	
	public void run(String arg) {
		
		ImagePlus original=IJ.openImage("/tmp/Monalisa2.jpg");
	
		
		
		Y=original.getHeight(); 
		X=original.getWidth(); 
		primeIP = new ColorProcessor(X,Y);
		int base[][]=original.getProcessor().getIntArray(); 
		
		
		//((ColorProcessor)primeIP).unsetUpper();
		setProcessor("Verifying", primeIP); 
		show();
	
		Genome hector=null;
		Population popaul=null; 
		try{
			Genome.setBounds(X, Y); 
			popaul=new Population(1000); 
		}
		catch(Exception e){
				System.out.println(e); 
				System.exit(0); 
		}
		Genome best=null;
		int nbGene=1000; 
		
		for(int v=0;v<nbGene;v++){// number of generations
			
			
			
		
		double fitnessMax=0; 
		double fitnessArray[]=new double[popaul.getSize()]; 
		double sumFit=0; 
		for(int i=0;i<popaul.getSize();i++){
			hector=popaul.get(i);
			
			double fitnessCandidat=fitness(hector,base,X,Y);
			sumFit+=fitnessCandidat; 
			fitnessArray[i]=sumFit; 
			if(fitnessCandidat>fitnessMax){
					fitnessMax=fitnessCandidat;
					best=hector; 
			}
		}
		System.out.println("Generation "+v+" Max fitness  "+fitnessMax+" Nb cercles : "+best.getLength()+ " Average fitness "+sumFit/popaul.getSize()); 
		System.out.println("Size of population : "+popaul.getSize());
		try{
		popaul.evolve(fitnessArray);
		}
		catch(Exception e){
			System.out.println(e); 
			System.exit(0); 
	}	
		// print the best of last generation
		primeIP.setIntArray(new int[X][Y]);
		for(int i=0;i<best.getLength();i++){
			Cercle ce=best.get(i); 
			primeIP.setColor(new java.awt.Color(ce.getRed(),ce.getGreen(),ce.getBlue()));
			primeIP.fillOval(ce.getX(),ce.getY(),ce.getRadius(),ce.getRadius()); 
		}
		setTitle("Generation "+v+" fitness "+fitnessMax); 
		updateAndDraw(); 
		
		}// end of nbGene evolutions
		
		}
	}	

	